— 2 min read
'인터페이스와 추상클래스의 차이'는 흔한 질문같지만 표면적인 차이 이상으로 들어가다보니 꽤 다양한 생각들을 만날 수 있었다.
Java8에서 인터페이스에 '디폴트 메서드'를 추가할 수 있게 되어서 둘의 차이점이 많지 않아졌다. 언제 무엇을 쓰는게 바람직한가를 좀더 자세히 살펴봤다.
먼저 기본적인 특징들을 살펴보자.
상수(static final ~) 와 추상메서드를 포함할 수 있다
1interface Barkable {2 public static final int BLABLA_CONSTANT = 1;3 public abstract void bark();4}
Java8부터 디폴트 메서드 (안에 구현까지 작성 가능)를 포함할 수 있다
디폴트 메서드: 인터페이스를 상속한 구현체에 공통으로 들어갈 코드를 디폴트 메서드에 작성하여 반복을 줄인다
1// java.util.List에 있는 디폴트 메서드23**default void replaceAll(UnaryOperator<E> operator) {4 Objects.requireNonNull(operator);5 final ListIterator<E> li = this.listIterator();6 while (li.hasNext()) {7 li.set(operator.apply(li.next()));8 }9}**
default method 제약사항
equals
나 hashCode
같은 Object의 메서드 정의한건 디폴트 메서드로 제공해서는 안된다.스태틱 메서드를 가질 수 있다
클래스.메서드()
로 호출하나의 구현체가 여러개의 인터페이스를 구현(implement)할 수 있다
abstract
키워드와 함께 선언한다.1abstract class Animal {2}
1public interface Iterable<T> {2 public default void forEach(Consumer<? super T> consumer) {3 for (T t : this) {4 consumer.accept(t);5 }6 }7}
대용량 SMS sender를 구현 - 여러 나라의 통신사들이 다른 tower를 갖고 있어서 각각 다른 구현이 필요 + 공통으로 지켜야할 규칙(DoNotDisturb모드인지 확인) 도 있는 상황일 때
SMS를 보내는 추상화된 코드:
1public void sendSMS(){2 establishConnectionWithYourTower();3 checkIfDoNotDisturbMode();4 // -- SMS 보내기 --5 destroyConnectionWithYourTower();6}78public void establishConnectionWithYourTower(){9 // 통신사마다 다르다10}1112public void checkIfDoNotDisturbMode(){13}14 15public void destroyConnectionWithYourTower(){16 // 통신사마다 다르다17}
구현
1abstract class SMSSender{2 3 abstract public void establishConnectionWithYourTower();4 5 public void sendSMS(){6 establishConnectionWithYourTower();7 checkIfDoNotDisturbMode();8 // -- SMS 보내기 --9 destroyConnectionWithYourTower();10 }11 12 abstract public void destroyConnectionWithYourTower();13 14 public void checkIfDoNotDisturbMode(){15 // 추상클래스 안에서 구현16 }17}1819/* SMSSender를 통신사 클래스들이 상속 */ 20class Vodafone extends SMSSender{21 @Override22 public void establishConnectionWithYourTower() {23 // Vodafone 방식으로 커넥션 맺기24 }25 26 @Override27 public void destroyConnectionWithYourTower() {28 // Vodafone 방식으로 커넥션 종료29 } 30}31 32class Airtel extends SMSSender{33 @Override34 public void establishConnectionWithYourTower() {35 }36 37 @Override38 public void destroyConnectionWithYourTower() {39 }40}
책 '이펙티브 자바'에서는 '추상클래스보다 인터페이스를 우선하라'고 하며 여러 이유와 예시 케이스들을 든다.
Comparable
을 구현하면, Comparable
을 구현한 인스턴스들끼리는 순서를 정할 수 있다고 선언하는 것.1// interface2public interface SingerSongWriter extends Singer, SongWriter {3 void actSensitive();4}56// abstract class7public abstract class SingerSongWriter {8 abstract AudioClip sing(Song s);9 abstract Song compose(int chartPosition);10 void actSensitive();11}
⇒ 인터페이스와 추상 골격 구현 (skeletal implementation) 클래스를 함께 제공하기